package com.zwk.gulimall.product.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zwk.common.constant.ProductConstant;
import com.zwk.common.exception.NoStockException;
import com.zwk.common.to.SkuHasStockTo;
import com.zwk.common.to.SkuReductionTo;
import com.zwk.common.to.SpuBoundTo;
import com.zwk.common.to.es.SkuEsModel;
import com.zwk.common.utils.R;
import com.zwk.gulimall.product.entity.*;
import com.zwk.gulimall.product.feign.ConponClient;
import com.zwk.gulimall.product.feign.SearchClient;
import com.zwk.gulimall.product.feign.WareClient;
import com.zwk.gulimall.product.service.*;
import com.zwk.gulimall.product.vo.Images;
import com.zwk.gulimall.product.vo.Skus;
import com.zwk.gulimall.product.vo.SpuSaveVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zwk.common.utils.PageUtils;
import com.zwk.common.utils.Query;

import com.zwk.gulimall.product.dao.SpuInfoDao;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

@Slf4j
@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Autowired
    private SkuImagesService skuImagesService;
    @Autowired
    private SpuImagesService spuImagesService;
    @Autowired
    private SpuInfoDescService spuDescService;
    @Autowired
    private ProductAttrValueService productAttrService;
    @Autowired
    private AttrService attrService;
    @Autowired
    private SkuInfoService skuService;
    @Autowired
    private SkuSaleAttrValueService skuAttrValueService;
    @Autowired
    private ConponClient conponClient;
    @Autowired
    private BrandService brandService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private WareClient wareClient;
    @Autowired
    private SearchClient searchClient;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );
        return new PageUtils(page);
    }

    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        LambdaQueryWrapper<SpuInfoEntity> wrapper = new LambdaQueryWrapper<>();
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)) {
            wrapper.and((w) -> {
                w.eq(SpuInfoEntity::getId, key).or().like(SpuInfoEntity::getSpuName, key);
            });
        }
        // status=1 and (id=1 or spu_name like xxx)
        String status = (String) params.get("status");
        if (!StringUtils.isEmpty(status)) {
            wrapper.eq(SpuInfoEntity::getPublishStatus, status);
        }

        String brandId = (String) params.get("brandId");
        if (!StringUtils.isEmpty(brandId) && !"0".equalsIgnoreCase(brandId)) {
            wrapper.eq(SpuInfoEntity::getBrandId, brandId);
        }

        String catelogId = (String) params.get("catelogId");
        if (!StringUtils.isEmpty(catelogId) && !"0".equalsIgnoreCase(catelogId)) {
            wrapper.eq(SpuInfoEntity::getCatalogId, catelogId);
        }

        /**
         * status: 2
         * key:
         * brandId: 9
         * catelogId: 225
         */

        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                wrapper
        );

        return new PageUtils(page);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void up(Long spuId) throws NoStockException {
        //1、获取公共信息
        //1.1获取所有spu中可被检索的attr参数并封装成esAttr
        List<ProductAttrValueEntity> baseAttrs = productAttrService.baseAttrlistforspu(spuId);
        List<Long> attrIds = baseAttrs.stream().map(attr -> attr.getAttrId()).collect(Collectors.toList());
        //查询出所有是快速查询的属性id
        List<Long> searchAttrIds = attrService.selectSearchAttrs(attrIds);
        Set<Long> attrSet = new HashSet<>(searchAttrIds);
        //返回是快速的规格参数和基本信息
        List<SkuEsModel.Attrs> esAttrs = baseAttrs.stream().filter(
                attr -> attrSet.contains(attr.getAttrId())
        ).map(
                attr -> new SkuEsModel.Attrs(attr.getAttrId(),attr.getAttrName(),attr.getAttrValue())
        ).collect(Collectors.toList());

        //2、获取sku信息，并将其与公共信息包装
        List<SkuInfoEntity> skuInfoEntities = skuService.getSkusBySpuId(spuId);
        //2.1：批量获取其他服务信息，如果每个sku都发起一次远程调用，将极耗费性能，所以采用批量获取sku库存信息
        //2.1.1批量获取sku库存信息，并放入stockMap中
        List<Long> skuIds = skuInfoEntities.stream().map(
                s->s.getSkuId()
        ).collect(Collectors.toList());
        R wareResponse=null;
        try {
            wareResponse= wareClient.getSkuHasStock(skuIds);
        }catch (Exception e){
            log.error("库存服务查询异常：原因{}",e);
        }
        List<SkuHasStockTo> hasStocks = (List<SkuHasStockTo>) wareResponse.getData(new TypeReference<List<SkuHasStockTo>>(){});
        if (hasStocks ==null|| hasStocks.size()==0) {
            throw new NoStockException("该商品没有库存，无法上架");
        }
        Map<Long, Boolean> stockMap = hasStocks.stream().collect(Collectors.toMap(SkuHasStockTo::getSkuId, SkuHasStockTo::getHasStock));
        //2.2封装成ES模型
        List<SkuEsModel> skuEsModels = skuInfoEntities.stream().map(sku -> {
            //组装需要的数据
            SkuEsModel esModel = new SkuEsModel();
            esModel.setSkuPrice(sku.getPrice());
            esModel.setSkuImg(sku.getSkuDefaultImg());
            //设置库存
            esModel.setHasStock(stockMap.get(sku.getSkuId()));
            //TODO 2、热度评分。0
            esModel.setHotScore(0L);

            BrandEntity brandEntity = brandService.getById(sku.getBrandId());
            esModel.setBrandName(brandEntity.getName());
            esModel.setBrandId(brandEntity.getBrandId());
            esModel.setBrandImg(brandEntity.getLogo());
            CategoryEntity categoryEntity = categoryService.getById(sku.getCatalogId());
            esModel.setCatalogId(categoryEntity.getCatId());
            esModel.setCatalogName(categoryEntity.getName());
            //设置检索属性
            esModel.setAttrs(esAttrs);
            BeanUtils.copyProperties(sku,esModel);
            return esModel;
        }).collect(Collectors.toList());
        //3、添加至es中
        searchClient.productStatusUp(skuEsModels);
        //4.修改spu状态
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        spuInfoEntity.setId(spuId);
        spuInfoEntity.setPublishStatus(ProductConstant.ProductStatusEnum.SPU_UP.getCode());
        this.updateById(spuInfoEntity);
    }

    /**
     * //TODO 还有遗留问题，高级篇完善。（事务，feign超时）
     * @param spuSaveVo
     */
    @Transactional
    @Override
    public void saveSpuInfo(SpuSaveVo spuSaveVo) {
        //1.保存spu基本信息
        SpuInfoEntity spuInfo = new SpuInfoEntity();
        BeanUtils.copyProperties(spuSaveVo,spuInfo);
        boolean save = this.save(spuInfo);
        //2.保存spu图片信息
        List<SpuImagesEntity> spuImageList = spuSaveVo.getImages().stream().map(
                image -> new SpuImagesEntity(spuInfo.getId(), image)
        ).filter(
                img-> !StringUtils.isEmpty(img.getImgUrl())
        ).collect(Collectors.toList());
        spuImagesService.saveBatch(spuImageList);
        //3.保存描述图片
        List<SpuInfoDescEntity> spuDescList = spuSaveVo.getDecript().stream().map(
                imageDecript -> new SpuInfoDescEntity(spuInfo.getId(), imageDecript)
        ).collect(Collectors.toList());
        spuDescService.saveBatch(spuDescList);
        //4.保存spu规格参数
        List<ProductAttrValueEntity> productAttrList = spuSaveVo.getBaseAttrs().stream().map(attr -> {
            ProductAttrValueEntity product = new ProductAttrValueEntity();
            product.setSpuId(spuInfo.getId());
            product.setAttrId(attr.getAttrId());
            AttrEntity attrEntity = attrService.getById(attr.getAttrId());
            product.setAttrName(attrEntity.getAttrName());
            product.setAttrValue(attr.getAttrValues());
            product.setQuickShow(attr.getShowDesc());
            return product;
        }).collect(Collectors.toList());
        productAttrService.saveBatch(productAttrList);
        //5.保存sku相关
        List<Skus> skus = spuSaveVo.getSkus();
        if (skus!=null){
            skus.forEach(sku  -> {
                //5.1保存sku基本信息
                SkuInfoEntity skuEntity = new SkuInfoEntity();
                BeanUtils.copyProperties(sku,skuEntity);
                skuEntity.setSpuId(spuInfo.getId());
                skuEntity.setCatalogId(spuInfo.getCatalogId());
                skuEntity.setBrandId(spuInfo.getBrandId());
                Optional<Images> first = sku.getImages().stream().filter(img -> img.getDefaultImg() == 1).findFirst();
                if (first.isPresent()){
                    skuEntity.setSkuDefaultImg(first.get().getImgUrl());
                }
                skuService.save(skuEntity);
                //5.2保存sku图片信息
                List<SkuImagesEntity> imagesEntities = sku.getImages().stream().map(
                        img -> new SkuImagesEntity(skuEntity.getSkuId(), img.getImgUrl(), img.getDefaultImg())
                ).collect(Collectors.toList());
                skuImagesService.saveBatch(imagesEntities);
                //5.3保存sku的销售属性
                List<SkuSaleAttrValueEntity> skuAttrValueList = sku.getAttr().stream().map(
                        attr -> new SkuSaleAttrValueEntity(skuEntity.getSkuId(), attr.getAttrId(), attr.getAttrName(), attr.getAttrValue())
                ).collect(Collectors.toList());
                skuAttrValueService.saveBatch(skuAttrValueList);
                //5.4处理积分服务
                SpuBoundTo spuBoundTo = new SpuBoundTo();
                spuBoundTo.setSpuId(spuInfo.getId());
                BeanUtils.copyProperties(spuSaveVo.getBounds(),spuBoundTo);
                conponClient.saveSpuBounds(spuBoundTo);
                //5.5处理满减服务
                SkuReductionTo skuReductionTo = new SkuReductionTo();
                BeanUtils.copyProperties(sku,skuReductionTo);
                skuReductionTo.setSkuId(skuEntity.getSkuId());
                conponClient.saveSkuReduction(skuReductionTo);
            });
        }
    }

}